#ifndef FLOW_TABLE_H
#define FLOW_TABLE_H

#include <stdio.h>
#include <stdint.h> 
#include <assert.h>

/*
//in case of identifiers collision
#define flow_key flow_key_hh
#define action action_hh
#define fow_entry flow_entry_hh
#define flow_table flow_table_hh
#define flow_entry_block flow_entry_block_hh
#define list_node list_node_hh
#define table table_hh
*/

#define MAX_PRIORITY          (1 << 16)
//The value is just for testing 
#define DEFAULT_BLOCK_SIZE    (1 << 1)
#define DEFAULT_BLOCK_NUM     (1 << 0)
#define DEFAULT_BLOCK_SPACING (1 << 0)

struct flow_key_hh
{
    uint8_t input_port:4;
    uint16_t frame_type;
    uint8_t src_mac[6];
    uint8_t dst_mac[6];
};

//struct nlattr
struct action_hh
{
    uint8_t type;
    uint8_t len;
};
/*uint8_t port;*/

struct flow_entry_hh
{
    int  priority;
    struct flow_key_hh *match;
    struct flow_key_hh *mask;
    struct action_hh *acts;
    int valid;
};

/*struct entry_list
{
    struct flow_entry *entry;
    struct entry_list *prev;
    struct entry_list *next;
};

struct flow_table
{
    int num_entry;
    //struct flow_entry *entry;
    struct entry_list *head;
};*/

struct flow_table_hh
{
        int num_entry; // the number of flow entry in flow table 
	struct flow_entry_hh *entries;   // an array of flow entry
	int num_block;
	struct list_node_hh *block;
	struct list_node_hh *block_last;
};

struct flow_entry_block_hh
{
	int num_entry;
	int priority;
	int start;
	int end;
};

typedef struct flow_entry_block_hh* nodeptr;

/*
TODO:The list_node structure is not convenience to use, 
I've considered, but got the wrong conclusion.
'list_node' should be member of struct flow_entry_block.
But implementing a linked list like this is a little troublesome,
if we really want to do this, we can use the kernel structure 
'hlist_head' and 'hlist_node'.The Linux kernel also defines some 
macros to operate them ,such as 'list_for_each_entry', 'container_of'
etc.
I think, we'd better use this simple data structure until we need a 
more complex one.
*/

//doubly linked list
struct list_node_hh
{
	nodeptr np;
	struct list_node_hh *next;
	struct list_node_hh *prev;
};

int init();
struct flow_entry_hh* construct_flow_entry(uint8_t input_port, uint16_t frame_type,
                                        uint8_t src_mac[6], uint8_t dst_mac[6], 
                                        int priority, struct action_hh *action);
struct action_hh* construct_action(uint8_t port);
int get_capacity();
int match_cmp(struct flow_key_hh*, struct flow_key_hh*);
void set_high_bits_16(uint32_t *num, int val);
void set_low_bits_16(uint32_t *num, int val);
int ensure_not_full();
int delete_flow_entry_full();
int get_high_bits_16(uint32_t val);
int get_low_bits_16(uint32_t val);
//uint32_t search_insert_index(struct flow_entry *entry);

//enum ofp_flow_mod_command{
//OFPFC_ADD = 0, /* New flow. */
//OFPFC_MODIFY = 1, /* Modify all matching flows. */
//OFPFC_MODIFY_STRICT = 2, /* Modify entry strictly matching wildcards and
//			   priority. */
//OFPFC_DELETE = 3, /* Delete all matching flows. */
//OFPFC_DELETE_STRICT = 4, /* Delete entry strictly matching wildcards and
//priority. */
//};

/*
For example, if a message to remove
entries is sent that has no match fields included, the OFPFC_DELETE command would delete all flow
entries from the tables, while the OFPFC_DELETE_STRICT command would only delete a flow entry that
applies to all packets at the specified priority.
							--openflow specification 1.3.5
*/

int sw_add_flow_entry(struct flow_entry_hh*);
int sw_delete_flow_entry(struct flow_entry_hh*);
int sw_delete_flow_entry_strict(struct flow_entry_hh*);
int sw_modify_flow_entry(struct flow_entry_hh*);
int sw_modify_flow_entry_strict(struct flow_entry_hh*);

struct list_node_hh* create_list_node();
int search_existing_priority(struct list_node_hh *block);
int search_around_block(struct list_node_hh *block);
int search_new_priority(struct list_node_hh *block_before, struct list_node_hh *block_after, int priority);
int search_no_vacancy(struct list_node_hh *block);
int move(struct list_node_hh *block_start, struct list_node_hh *block_end);
int search_insert_index(struct flow_entry_hh *entry);
void print_mac(uint8_t mac[6]);
void print_flow_entry(struct flow_entry_hh *entry);
struct list_node_hh* insertion(struct list_node_hh *node);
void sort_list();
void list_insert_node(struct list_node_hh *cur, struct list_node_hh *inserted);

//The match fields and action type we support so far,we should call the function--hw_properties() to init them.
extern int oxm_ofb_flow_key[40], ofp_action_type[28], capacity;
//The global flow table
extern struct flow_table_hh *table_hh;
extern struct flow_entry_hh *entry_hh;

/*
//in case of identifiers collision
#undef flow_key 
#undef action 
#undef fow_entry 
#undef flow_table 
#undef flow_entry_block
#undef list_node 
#undef table
*/

#endif
